package com.yungu.swift.admin.handler;

import com.yungu.swift.admin.base.GatewayHeader;
import com.yungu.swift.admin.base.HttpServletRequestWrapper;
import com.yungu.swift.admin.consts.GatewayErrorEnum;
import com.yungu.swift.base.ResponseData;
import com.yungu.swift.utils.JsonUtils;
import com.yungu.swift.utils.Md5Utils;
import com.yungu.swift.utils.ParamUtil;
import com.yungu.swift.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.*;
import java.util.*;

/**
 * @author : cuixiuyin
 * @date : 2019/6/21
 */
@Slf4j
public class SignHandler extends HandlerInterceptorAdapter {

    /**
     * 签名加密密钥
     */
    private final static String AUTH_KEY = "fffa2a879e62e198924a95dc150dc33823bd0bf7abd3a20fff605f297ae9333804699723a6219048";
    private final static String GET = "GET";
    private final static String POST = "POST";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String sign = request.getHeader(GatewayHeader.sign);
        String ts = request.getHeader(GatewayHeader.ts);
        response.setContentType("application/json;charset=UTF-8");
        // 验签
        if (StringUtils.isEmpty(sign)) {
            GatewayErrorEnum loginSignLack = GatewayErrorEnum.LOGIN_SIGN_LACK;
            response.getWriter().print(JsonUtils.writeJsonStr(ResponseData.buildErrorResponse(loginSignLack.getCode(), loginSignLack.getMsg())));
            return false;
        }
        String encodeMd5 = "";
        String method = request.getMethod();
        //请求是JSON格式数据
        if (POST.equals(method) && request instanceof HttpServletRequestWrapper) {
            HttpServletRequestWrapper requestWrapper = (HttpServletRequestWrapper) request;
            String bodyStr = getBodyString(requestWrapper.getReader());
            encodeMd5 = checkJsonParam(ts, bodyStr);
        }
        //请求是文件流的数据
        if (POST.equals(method) && request.getContentType().contains(MediaType.MULTIPART_FORM_DATA_VALUE)) {
            Collection<Part> parts = request.getParts();
            Map<String, String[]> paramMap = new HashMap<>(8);
            for (Part part : parts) {
                if (part.getContentType() != null) {
                    paramMap.put(part.getName(), new String[]{Md5Utils.encode(part.getInputStream())});
                    continue;
                }
                paramMap.put(part.getName(), new String[]{stream2Str(part.getInputStream())});
            }
            encodeMd5 = checkFormParam(ts, paramMap);
        }
        if (GET.equals(method)) {
            Map<String, String[]> paramMap = request.getParameterMap();
            encodeMd5 = checkFormParam(ts, paramMap);
        }
        log.info("----------url:{}", request.getRequestURI());
        log.info("---------sign:{}", sign);
        log.info("---------encodeMd5:{}", encodeMd5);
        if (!sign.equals(encodeMd5)) {
            GatewayErrorEnum signFailed = GatewayErrorEnum.LOGIN_SIGN_FAILED;
            response.getWriter().print(JsonUtils.writeJsonStr(ResponseData.buildErrorResponse(signFailed.getCode(), signFailed.getMsg() + ", " + encodeMd5)));
            return false;
        }
        return super.preHandle(request, response, handler);
    }

    private String stream2Str(InputStream inputStream) {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"))) {
            String line;
            StringBuffer buffer = new StringBuffer();
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            return buffer.toString();
        } catch (UnsupportedEncodingException e) {
            log.error("SignHandler stream2Str UnsupportedEncodingException", e);
        } catch (IOException e) {
            log.error("SignHandler stream2Str IOException", e);
        }
        return "";
    }


    private String getBodyString(BufferedReader br) throws IOException {
        StringBuffer buffer = new StringBuffer();
        String line;
        while ((line = br.readLine()) != null) {
            buffer.append(line);
        }
        br.close();
        return buffer.toString();
    }

    /**
     * JSON格式请求参数加密是否一致
     *
     * @return
     */
    private String checkJsonParam(String ts, String jsonStr) {
        Map<String, Object> map = new HashMap<>(16);
        map.put("key", AUTH_KEY);
        map.put("ts", Long.parseLong(ParamUtil.defaultIfNull(ts, "0")));
        log.info("---------content:{},{}", JsonUtils.toJSONString(map), jsonStr);
        return Md5Utils.encode(JsonUtils.toJSONString(map) + jsonStr);
    }

    /**
     * form 表单格式请求参数加密是否一致
     *
     * @param paramMap
     * @return
     */
    private String checkFormParam(String ts, Map<String, String[]> paramMap) {
        List<String> paramKeyList = new ArrayList<>(paramMap.keySet());
        Collections.sort(paramKeyList);
        String paramStr = "";
        for (int i = 0; i < paramKeyList.size(); i++) {
            String paramKey = paramKeyList.get(i);
            String paramVal = paramMap.get(paramKey)[0];
            paramStr += paramKey + "=" + paramVal + "&";
        }
        Map<String, Object> map = new HashMap<>(16);
        map.put("key", AUTH_KEY);
        map.put("ts", Long.parseLong(ParamUtil.defaultIfNull(ts, "0")));
        paramStr = JsonUtils.toJSONString(map) + StringUtils.removeEnd(paramStr, "&");
        log.info("---------paramStr:{}", paramStr);
        return Md5Utils.encode(paramStr);
    }
}
